import glob
import hashlib
import os

from src.log.logger import logger
from src.tools.executecmd import ExecuteCmd
from config.constants import NO_NEED_CHECK_DEP


class RpmInfoQuery:
    """
    Provide common query funcs for rpm
    """
    
    @staticmethod
    def query_rpm_depends(rpm_path):
        """
        query depends info of rpm_path
        Args:
            rpm_path:
        Returns:
            rpm_depends:
        """
        
        rpm_depends = []
        rpm_query_cmd = f"rpm -qp --requires {rpm_path}"
        output = ExecuteCmd.cmd_output(rpm_query_cmd.split())
        if  output is None:
            logger.warning("No info")
            return []
        
        rpm_depends = output.strip().split('\n')
        return rpm_depends
    
    @staticmethod
    def query_rpms_depends(rpms: list):
        """
        query depends info of rpms
        Args:
            rpms:
        Returns:
            rpms_depends: dict
        """
        
        rpms_depends = dict()
        for rpm in rpms:
            rpm_depends = RpmInfoQuery.query_rpm_depends(rpm)
            logger.info("get rpm depends for:%s====[%s]", rpm, rpm_depends)
            rpms_depends[rpm] = rpm_depends
        return rpms_depends
    
    
    @staticmethod
    def query_rpm_provides(rpm_path):
        """
        query provides info of rpm_path
        Args:
            rpm_path:
        Returns:
            rpm_provides
        """
        
        rpm_provides = dict()
        rpm_query_cmd = f"rpm -qp --provides {rpm_path}"
        output = ExecuteCmd.cmd_output(rpm_query_cmd.split())
        if  output is None:
            logger.warning("No info")
            return {}
        
        output_lines = output.strip().split('\n')
        # rpm_file_name = os.path.basename(rpm_path)
        # rpm_name = rpm_file_name.rsplit('-', 2)[0]
        for line in output_lines:
            rpm_provides[line.strip()] = rpm_path
            
        return rpm_provides
        
    @staticmethod
    def query_rpms_provides(rpms):
        """
        query depends info of rpms
        Args:
            rpms:
        Returns:
            rpms_provides
        """
        
        rpms_provides = dict()
        for rpm in rpms:
            rpm_provides = RpmInfoQuery.query_rpm_provides(rpm)
            logger.info("get rpm provides for:%s====[%s]", rpm, rpm_provides)
            rpms_provides.update(rpm_provides)
        return rpms_provides
    
    @staticmethod
    def query_dep_what_provides(dep, rpms_provides: dict, repo=''):
        """
        query what provides dep
        Args:
            dep:
        Returns:
        
        """
        
        logger.info("dnf repoquery --whatprovides %s", dep)
        rpm_query_cmd = f"dnf repoquery --whatprovides {dep}"
        output = ExecuteCmd.cmd_output(rpm_query_cmd.split())
        if  output is None:
            logger.warning("No info")
            return ""
        
        output_lines = output.strip().split('\n')
        if len(output_lines) < 2:
            return ""
        
        dep_what_provides = output_lines[1].rsplit('-', 2)[0]
        return dep_what_provides
    
    @staticmethod
    def get_name_with_version(rpm_name):
        """
        get name with version from rpm_name
        Args:
        
        Returns:
        
        """
        name_version = rpm_name.rsplit('-', 1)[0]
        return name_version
    
    @staticmethod
    def query_rpms_info(rpms):
        """
        query rpms infos
        Args:
            rpms:
        Returns:
        
        """
        
        rpms_info = dict()
        for rpm in rpms:
            rpm_info = RpmInfoQuery.get_rpm_query_info(rpm)
            logger.info("get rpm info for:%s====[%s]", rpm, rpm_info)
            rpms_info[rpm] = rpm_info
        return rpms_info
    
    @staticmethod
    def get_rpm_query_info(rpm_path):
        """
        get  home page of rpm_path
        Args:
            rpm_path:
        Returns:
            rpm_info_fields:
        """
        
        rpm_query_cmd = f"rpm -qi {rpm_path}"
        output = ExecuteCmd.cmd_output(rpm_query_cmd.split())
        if  output is None:
            logger.warning("No info")
            return {}
        
        rpm_info_fields = {}
        output_lines = output.strip().split('\n')        
        key = None
        value = []  # 使用列表来存储value，因为value可能跨越多行
        for line in output_lines:
            if ':' in line:
                # 如果当前行包含冒号，并且之前已经有一个key（不是第一个key-value对）
                if key is not None:
                    # 将之前累积的value（可能是多行）拼接成一个字符串，并存储在字典中
                    rpm_info_fields[key.strip()] = ' '.join(value).strip()  # 使用strip()去除可能的空白字符
                # 设置新的key和重置value列表
                key, value_part = line.split(':', 1)
                value = [value_part.strip()]  # 添加到value列表并去除首尾的空白字符
            elif key is not None:
                # 如果当前行不包含冒号，但之前已经设置了一个key，则这行是value的一部分
                value.append(line.strip())  # 添加到value列表并去除首尾的空白字符
            logger.info("get %s: %s", key, value)
            
        if key is not None:
            rpm_info_fields[key.strip()] = ' '.join(value).strip()
            logger.info("get %s: %s", key, value)
            
        rpm_info_fields['sha256sum'] = RpmInfoQuery.get_checksum(rpm_path)

        return rpm_info_fields
    
    @staticmethod
    def get_only_name(rpm_file_name):
        """
        get name from rpm_file_name
        Args:
        
        Returns:
        
        """
        name = rpm_file_name.rsplit('-', 2)[0]
        return name
    
    @staticmethod
    def get_only_version(rpm_file_name):
        """
        get version from rpm_file_name
        Args:
        
        Returns:
        
        """
        version = rpm_file_name.rsplit('-', 2)[1]
        return version
    
    @staticmethod
    def get_checksum(file_path):
        """
        get sha256sum of file_path
        Args:
            file_path:
        Returns:
        
        """
    
        # 创建一个新的sha256 hash对象
        sha256_hash = hashlib.sha256()

        # 打开文件以进行读取
        with open(file_path, "rb") as f:
            # 读取文件内容并更新哈希对象
            for byte_block in iter(lambda: f.read(4096), b""):
                sha256_hash.update(byte_block)

        # 获取十六进制哈希值
        hex_dig = sha256_hash.hexdigest()
        logger.info(hex_dig)
        return hex_dig
    
    @staticmethod
    def extract_rpm(rpm_path, extract_dir):
        """
        extract rpm
        Args:
            extract_dir
        Returns:
        
        """
        
        if not os.path.exists(extract_dir):
            os.makedirs(extract_dir)
        # 使用rpm2cpio和cpio解压RPM包
        logger.info("Start cpio rpm: %s", rpm_path)
        os.system(f"cd {extract_dir}; rpm2cpio {rpm_path} | cpio -idmv")
        # shutil.rmtree(extract_dir)  # 清理临时目录

    @staticmethod
    def compute_md5(file_path):
        """
        compute md5sum of file_path
        Args:
            file_path:
        Returns:
        
        """
        
        hash_object = hashlib.md5()
        if not os.path.exists(file_path):
            logger.warning("maybe soft link: %s", file_path)
            return ""
        with open(file_path, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                hash_object.update(chunk)
        return hash_object.hexdigest()
    
    @staticmethod
    def check_operator(line):
        operators = ['=', '<', '>', '<=', '>=']
        contain_oe = ''
        for oe in operators:
            if 'oe' in line:
                return True
        return False
    
    @staticmethod
    def check_no_need_process_dep(dep):
        """
        check dep if no need to be processed
        Args:
            dep
        Returns:
        
        """
        
        for special_dep in NO_NEED_CHECK_DEP:
            if special_dep in dep:
                return True
        return False
    
    @staticmethod
    def find_files(directory, suffix):
        """
        find files end with suffix path form directory
        Args:
            directory:
        Returns:
        
        """
        
        files_paths = glob.glob(os.path.join(directory, '**', '.'.join(['*', suffix])), recursive=True)
        return files_paths
